package model.winding;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

import model.IManufacturingMethodWithPartProcessesAndTools;
import model.ManufacturingMethod;
import model.PartProcess;
import model.auxillary.Parameter;
import model.auxillary.ParameterCollection;
import model.auxillary.ParameterList;
import model.auxillary.ParameterList.ParameterType;
import model.auxillary.Tool;

/**
 * The class {@code NeedleWinding} models a needle winding process.
 * @author Sebastian Perlwitz
 *
 */
public class NeedleWinding extends ManufacturingMethod
		implements IManufacturingMethodWithPartProcessesAndTools {

	/**
	 * To create a new instance of a {@code NeedleWinding} process.
	 * @param name the name of the process.	 
	 */
	public NeedleWinding(String name) {
		super(name, "Nadelwickeln (Runddraht)" + getManuMethodsCreatedCount());
		super.addParameters();
		addParameters();
		addPartProcess();
		addTool();
		subType = SubType.NEEDLE_WINDING;
	}
	
	@Override
	protected void addParameters() {
		List<Parameter> newParams = new ArrayList<Parameter>();
		
		newParams.add(new Parameter(
				"Zugfestigkeit Drahtmaterial",
				"Rm",
				"<html>R<sub>m</sub></html>",
				"<html>[N/mm<sup>2</sup>]</html>",
				true,
				this));
		
		newParams.add(new Parameter(
				"Drahtzugkraft",
				"F_DZ",
				"<html>F<sub>DZ</sub></html>",
				"<html>[N]</html>",
				true,
				this));
		
		parameters.addParameters(ParameterType.MATERIAL_PARAMETER, newParams);		
	}

	@Override
	public ParameterList addPartProcess() throws IndexOutOfBoundsException {
		
		if (partProcesses.size() == MAX_PART_PROCESSES) {
			throw new IndexOutOfBoundsException("Maximum number of allowed "
					+ "part processes is reached.");
		}
		PartProcess newProcess = new PartProcessNeedleWinding(
				this,
				"PP_" + getPartProCount() + "_" + this.getID(),
				getPartProCount(),
				"Wickelgeometriebeschreibung");
		partProcesses.add(newProcess);		
		return newProcess.getParameters();
	}

	@Override
	public ParameterCollection addTool() {
		int toolIndex = parameters.getTools().size();
		List<Parameter> newParams = new ArrayList<Parameter>();		
		
		newParams.add(new Parameter(
				"Masse Drahtverleger",
				"m_DV," + toolIndex,
				"<html>m<sub>DV," + toolIndex + "</sub></html>",
				"<html>[kg]</html>",
				true,
				this));
		
		newParams.add(new Parameter(
				"Maximale Verfahrgeschwindigkeit",
				"v_max," + toolIndex,
				"<html>v<sub>max,DV," + toolIndex + "</sub></html>",
				"<html>[mm/s]</html>",
				true,
				this));
		
		return parameters.addTool(newParams);
	}

	@Override
	public void calculate() {

		error = false;
    	aborted = false;
    	
    	double Rm = getParameter("Rm",
				ParameterType.MATERIAL_PARAMETER).getValue();
    	double F_DZ = getParameter("F_DZ",
				ParameterType.MATERIAL_PARAMETER).getValue();
    	double eta_ges = getParameter("eta_ges",
				ParameterType.PROCESS_PARAMETER).getValue();
    	
    	// Calculation of values of the part processes.
    	for (PartProcess partProcess : partProcesses) {    		
    		PartProcessNeedleWinding ppnw =
    				(PartProcessNeedleWinding) partProcess;
    		
    		// Calculation of physical energy minimum.
    		double totalNumberWindings = partProcess.getParameter(
    				"totalNumberWindings",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		double d = partProcess.getParameter("d",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		double lx = partProcess.getParameter("lx",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		double ly = partProcess.getParameter("ly",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		
    		double eMinPhyPP = ppnw.computePhysMinEnergyNeedleWindingPP(
    				totalNumberWindings, Rm, d, lx, ly);
    		
    		// Calculation of technological energy minimum.
    		double m_DV = partProcess.getParameter("m_DV",
    				ParameterType.TOOL_PARAMETER).getValue();
    		double s_yDV = partProcess.getParameter("s_yDV",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		double s_xDV = partProcess.getParameter("s_xDV",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		double v_max = partProcess.getParameter("v_max",
    				ParameterType.TOOL_PARAMETER).getValue();
    		
    		double currentMoveSpeed = 0.06 * v_max;
    		double eLiftPP = ppnw.computeLiftEnergyPP(
    				totalNumberWindings, m_DV, s_yDV, s_xDV);
    		double eAccelerationPP = ppnw.computeAccelerationPP(
    				m_DV, currentMoveSpeed, totalNumberWindings);
    		double eWireBreakPP = ppnw.computeWireBreakEnergyPP(
    				F_DZ, totalNumberWindings, lx, ly);
    		double eMinTechPP = ppnw.computeTechMinEnergyNeedleWindingPP
    				(eMinPhyPP, eLiftPP, eAccelerationPP, eWireBreakPP);
    		
    		// Calculation of the real energy minimum.
    		double eMinRealPP = ppnw.computeRealMinEnergyNeedleWindingPP(
    				eMinTechPP, eta_ges);
    		
    		// Setting the results of this part process.
    		double eActPP = partProcess.getParameter("E_ist",
    				ParameterType.GEOMETRY_PARAMETER).getValue();
    		
    		ppnw.setPhysMinEnergyPartProcess(eMinPhyPP);
    		ppnw.setTechMinEnergyPartProcess(eMinTechPP);
    		ppnw.setRealMinEnergyPartProcess(eMinRealPP);
    		
    		ppnw.setPhysEffectivenessPartProcess(eActPP, eMinPhyPP);
    		ppnw.setTechnEffectivenessPartProcess(eActPP, eMinTechPP);
    		ppnw.setRealEffectivenessPartProcess(eActPP, eMinRealPP);
    	}
    	
    	// Setting the results of the process.
    	double eAct = getParameter("E_ist",
				ParameterType.PROCESS_PARAMETER).getValue();
    	
    	double eMinPhy = setPhysMinEnergy();
    	double eMinTech = setTechMinEnergy();
    	double eMinReal = setRealMinEnergy();
    	
    	setPhysicalEffectiveness(eAct, eMinPhy);
    	setTechnologicalEffectiveness(eAct, eMinTech);
    	setRealEffectiveness(eAct, eMinReal);
    	
    	if(error || aborted) {
            calculated = false;
        } else {
            calculated = true;
        }
	}

	@Override
    public String[] getToolNames() {
    	return parameters.getToolNames();
    }
    
    @Override
    public String[] getToolIDs() {
    	return parameters.getToolIDs();
    }
    
    @Override
    public void setTool(String partProcessID, String toolName) {
    	PartProcessNeedleWinding partProc = 
    			(PartProcessNeedleWinding) getPartProcess(partProcessID);
    	Tool tool = parameters.getTool(toolName);
    	partProc.setTool(tool);
    }
    
    @Override
    public int getToolIndex(String partProcessID) { 	
    	try {
        	// Get it's tool.
    		Tool tool = getPartProcess(partProcessID).getTool();
        	// Return the index.
        	return parameters.getToolIndex(tool);
    	} catch (NoSuchElementException nse) {
    		return 0;
    	}
    }

    @Override
	public ParameterType[] getInputParameterTypes() {
		ParameterType[] result = new ParameterType[4];
		result[0] = ParameterType.PROCESS_PARAMETER;
		result[1] = ParameterType.MATERIAL_PARAMETER;
		result[2] = ParameterType.GEOMETRY_PARAMETER;
		result[3] = ParameterType.TOOL_PARAMETER;
		return result;
	}
    
}
